package com.aifast.core.db.config;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import com.aifast.common.cache.annotations.AutoCache;
import com.aifast.common.cache.util.RedisUtil;
import com.aifast.common.global.Const;
import com.aifast.core.db.enums.DataSourcePool;
import com.aifast.common.properties.Setting;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.hikaricp.HikariCpPlugin;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @Author fujian
 * @since 2022/9/2 16:33
 * 内置自动缓存操作
 */
@Slf4j
@Configuration
public class ActiveRecordConfig {

    @Autowired
    private Setting setting;
    @Autowired
    private DynamicDataSourceProperties dynamicDataSourceProperties;

    @Value("${ai.jfinal-active-record.enable}")
    private boolean enable;

    private ApplicationContext context = SpringUtil.getApplicationContext();

    /**
     * 多数据源配置
     */
    @Bean
    public void dynamicStart(){
        if(!enable)return;
        log.info("***开始初始化JfinalActiveRecord*************************************");
        Map<String, DataSourceProperty> datasourceMap = dynamicDataSourceProperties.getDatasource();
        datasourceMap.forEach((k,v)->{
            HikariCpPlugin hp = new HikariCpPlugin(v.getUrl(), v.getUsername(), v.getPassword());
            ActiveRecordPlugin arp = new ActiveRecordPlugin(convertDataSourceName(k),hp);
            hp.start();
            arp.start();

            SpringUtil.registerBean(StrUtil.join("_","ActiveRecord",convertDataSourceName(k)),arp);
        });
    }

    private static String convertDataSourceName(String name){
        return StrUtil.equals(DataSourcePool.MASTER,name) ? "main" : name;
    }

    /**
     * 单数据源配置
     * @return
     */
//    @Bean
    public ActiveRecordPlugin start() {
        HikariCpPlugin hp = new HikariCpPlugin(setting.getUrl(), setting.getUsername(), setting.getPassword());
        ActiveRecordPlugin arp = new ActiveRecordPlugin(hp);
        hp.start();
        arp.start();
        autoCacheRunner();
        return arp;
    }


    private void autoCacheRunner() {
        if (!setting.getAutoCache()) { // 配置不打开自动缓存开关 不进行任何操作
            return;
        }
        log.info("自动缓存机制启动 开始扫描注解@AutoCache");
        String[] names = context.getBeanNamesForAnnotation(AutoCache.class);
        for (String name : names) {
            Object bean = SpringUtil.getBean(name);
            AutoCache autoCache = bean.getClass().getAnnotation(AutoCache.class);
            String tableName = StrUtil.isBlank(autoCache.tableName()) ? getTableName(name) : autoCache.tableName();
            setCache(tableName, autoCache);
        }

    }

    private static String getTableName(String beanName) {
        int service = beanName.indexOf("Service");
        String substring = beanName.substring(0, service);
        return StrUtil.toUnderlineCase(substring);
    }

    private void setCache(String tableName, AutoCache autoCache) {
        List<Record> query = Db.findAll(tableName);
        if (query.size() == 0) {
            return;
        }
        Set<String> keys = RedisUtil.keys(RedisUtil.getAutoCacheTableKey(tableName) + "*");
        if(query.size() == keys.size()){
            return;
        }
        List<JSON> collect = query.stream().map(i -> JSONUtil.parse(MapUtil.toCamelCaseMap(i.getColumns()))).collect(Collectors.toList());
//        collect.forEach(i -> RedisUtil.hset(RedisUtil.getAutoCacheTableKey(tableName), i.getByPath(autoCache.cacheKey()).toString(), i));
        collect.forEach(i -> {
            String key = RedisUtil.getAutoCacheTableKey(tableName, i.getByPath(autoCache.cacheKey()).toString());
            if(RedisUtil.exists(key)){
                return;
            }
            RedisUtil.set(key, JSONUtil.toJsonStr(i), Const.EIGHT_HOUR);
        });

    }


}
